/*
 * Copyright (c) 2003-2010, Live Media Pty. Ltd.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted
 * provided that the following conditions are met:
 *
 *  1. Redistributions of source code must retain the above copyright notice, this list of
 *     conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright notice, this list of
 *     conditions and the following disclaimer in the documentation and/or other materials
 *     provided with the distribution.
 *  3. Neither the name of Live Media nor the names of its contributors may be used to endorse
 *     or promote products derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package com.colony.concurrent;

/**
 *  A worker is a thread that does work for the application.
 */
public class Worker
extends Thread
{
   private boolean _started;
   private boolean _active;
   private Runnable _wi;
   private boolean _stayAlive;
   private ThreadPool _pool;
   private long _timeout;

   public Worker()
   {
   	this.setDaemon( true );
      _started = false;

      _active = false;
      _wi = null;
      _stayAlive = true;
      _pool = null;
      _timeout = 10000;
   }

	/**
	 * When a Worker is started its important to wait for it to start
	 * before assigning work to it.  The first thing the thread does
	 * is call started to let any waiting thread know.
	 */
   protected synchronized void waitStart()
   {
      while ( _started == false )
      {
         try
         {
            wait();
         }
         catch ( Exception ex )
         {
         }
      }
   }

   private synchronized void started()
   {
      _started = true;
      notifyAll();
   }

   public void run()
   {
      started();

      while ( _stayAlive )
      {
         try
         {
         	
         	// If we're active
            if ( waitActive() )
            {
            	if ( _wi == null )
            		System.err.println( "Error. Invalid state" );
            		
               _wi.run();
               deactivate();
            }         

			// The below must be in a syncrhonized block.  There is a small race condition
			// where the thread is busy returning itself to the pool because its finished
			// doing work and then is activated.  _active becomes true, however _wi has
			// been set to null.

			synchronized( this )
			{

	            // If we're still not active we must have timeout.  Check in and continue.
	            if ( _active == false && _wi != null )
	            {
	                _pool.returnThread( this );  
	                _wi = null;
	            }
	
	            // we're in the thread pool and still nothing to do..  lets timeout.
	            else if ( _active == false && _wi == null )
	            {
	                _pool.workerTimeout( this );
	            }
            
			}
         } 
         catch ( Exception ex ) 
         {
            // Arrgghhh!!
    		ex.printStackTrace();
    		deactivate();
         }
         catch ( Throwable th )
         {
            th.printStackTrace();
            deactivate();
         }
      }  
   }

   private boolean waitActive()
   {
      synchronized( this )
      {
         if ( _active == true ) return _active;

         try
         {
            wait( _timeout );
         }
         catch( Exception ex )
         {
            System.out.println( "ex" + ex.getMessage() );
         }
         return _active;
      }
   }
   
	/**
	 * After the thread has finished doing some work with a Worker
	 * it becomes inactive, waiting for more work.  The Worker
	 * also becomes inactive if any exception is caught.
	 */
	private void deactivate()
	{
		synchronized( this )
		{
			_active = false;
		}
	}

	/**
	 * Activate this thread with a worker.
	 */
	public void activate( Runnable wi )
	{

		if ( wi == null )
			throw new NullPointerException();
   		
		synchronized( this )
		{
			// If we're already active, we can't accept work.
			if ( _active == true )
				throw new IllegalStateException();

			_wi = wi;
			_active = true;
			notify();
		}
   }

   protected void stopWorker( )
   {
		synchronized( this )
		{
			_wi = null;
			_stayAlive = false;
			notify();
		}
	}


   /** 
    * This should only be ever called by the ThreadPool object.
    * Its not syncronized because the thread should either be in
    * inactive state and getting read to be activated or the worker thread
    * is returning itself after timeout.  assert would be good here.
    */
	protected void setOwner( ThreadPool p, long timeout )
	{
		_pool = p;
		_timeout = timeout;
	}

}
